package cn.duxiaod.demo.multithread;

import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.*;

public class MultiThreadTest {

    public static void main(String[] args) {
        /**
         * Object lock = new Object();
         * lock.wait();//交出对象锁，允许其他线程获取锁
         * lock.notify();//唤醒wait的线程
         *
         * CountDownLatch: 一个线程(或者多个)， 等待另外N个线程完成某个事情之后才能执行。
         * CyclicBrrier: N个线程相互等待，任何一个线程完成之前，所有的线程都必须等待。
         */
        //1:a,b线程同时进行
//        demo1();
        //2:a线程执行完成后执行b线程
//        demo2();
        //3:两个线程交叉有序进行
//        demo3();
        //4:a,b,c三个线程同时执行，执行完成后d开始执行
//        runDAfterABC();
        //5:3个运动员给自准备，都准备好了考试比赛
//        runABCWhenAllReady();
        //6:利用Callable和FuterTask获取子线程的执行结果
        doTaskWithResultInWorker();
    }

    /**
     * 利用Callable和FuterTask获取子线程的执行结果
     */
    private static void doTaskWithResultInWorker() {
        //计算1-100的和
        Callable<Integer> callable = new Callable() {
            @Override
            public Integer call() throws Exception {
                int result = 0;
                System.out.println("task start");
                for (int i = 1; i <= 100; i++) {
                    result += i;
                }
                System.out.println("task finish and return result!");
                return result;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();
        try {
            System.out.println("Before futureTask.get();");
            System.out.println("Result:"+futureTask.get());
            System.out.println("After futureTask.get();");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 3个运动员给自准备，都准备好了考试比赛
     */
    private static void runABCWhenAllReady() {
        int runner = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
        final Random random = new SecureRandom();
        for (char runnerName='a'; runnerName <= 'c'; runnerName++) {
            final String rN = String.valueOf(runnerName);
            new Thread(()->{
                long prepareTime = random.nextInt(10000)+100;
                System.out.println(rN+" is prepare "+prepareTime);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    System.out.println(rN + " is prepared, waiting for others");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(rN + " starts running"); // 所有运动员都准备好了，一起开始跑
            }).start();
        }
    }

    //a,b线程同时进行
    public static void demo1() {
        Thread a = new Thread(()->{
            printNumber("A");
        });
        Thread b = new Thread(() -> {
            printNumber("B");
        });
        a.start();
        b.start();
    }

    /**
     * A、B线程顺序执行
     */
    public static void demo2() {
        Thread a = new Thread(()->{
            printNumber("A");
        });
        Thread b = new Thread(() -> {
            System.out.println("b开始等待a");
            try {
                a.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            printNumber("B");
        });
        a.start();
        b.start();
    }

    /**
     * 两个线程交叉有序进行
     */
    public static void demo3() {
        Object lock = new Object();
        Thread a = new Thread(()->{
            synchronized (lock){
                System.out.println("A 1");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("A 2");
                System.out.println("A 3");
            }
        });
        Thread b = new Thread(() -> {
            synchronized (lock) {
                System.out.println("B 1");
                System.out.println("B 2");
                System.out.println("B 3");
                lock.notify();
            }
        });
        a.start();
        b.start();
    }

    public static void runDAfterABC(){
        CountDownLatch countDownLatch = new CountDownLatch(3);
        new Thread(()->{
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("all done,d is work!");
        }).start();

        for (char threadName='a'; threadName <= 'c'; threadName++) {
            final String tN = String.valueOf(threadName);
            new Thread(()->{
                System.out.println(tN+" is work!");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(tN+" is finish!");
                countDownLatch.countDown();
            }).start();
        }
    }

    public static void printNumber(String threadName){
        int i = 0;
        while (i++ < 3) {
            try {
                Thread.sleep(100);
                System.out.println("threadName " + threadName + " print:" + i);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
